<?php

namespace App\Model;

use EasySwoole\EasySwoole\Config;
use EasySwoole\EasySwoole\EasySwooleEvent;
use EasySwoole\ORM\AbstractModel;
use EasySwoole\ORM\Utility\PreProcess;

class Common extends AbstractModel
{
    const TIMESTAMPS = false,
        PRIMARYKEY = '';
    public $primaryKey = self::PRIMARYKEY;//主键

    protected $tableName = '';

    // 都是非必选的，默认值看文档下面说明
    protected $autoTimeStamp = self::TIMESTAMPS;
    protected $createTime    = 'created_time';
    protected $updateTime    = 'updated_time';

    protected $connectionName = 'thinkphp';

    public $is_delete    = 1;//是否删除
    public $delete_field = 'is_delete';//删除字段


    // 关联模型
    public $withModel = [],
        // 详情的模型
        $detailWithModel = [];

    public function __construct(array $data = [])
    {
        parent::__construct($data);

        if (empty($this->tableName)) {
            // 数据表前缀
            $prefix = Config::getInstance()->getConf('Mysql.' . $this->connectionName . '.prefix');

            // 数据表名 按照模型转化成 下划线+小写
            $model_fie_name = explode('\\', get_called_class());
            $tableName      = $prefix . strtolower(string_underscore_lowercase(end($model_fie_name))); // 如果表名存在大写，那么自动转换成：下划线+小写

            // 设置数据表名必须为复数
            $this->tableName = get_string_pluralize($tableName); // 复数
        }

        // 默认加载Where
        $this->operationWhere();
    }

    public function paginate(int $limit = 10, int $page = 0): array
    {
        $page = $page <= 0 ? 1 : $page;

        $model = $this->limit(($page - 1) * $limit, $limit)->withTotalCount(); //获取数据

        $data = $model->select();

        //获取查询结果对象
        $lastResult = $model->lastQueryResult();

        //获取查询数据总数,查询时需要调用`withTotalCount`才可以使用该方法
        $count = $lastResult->getTotalCount();

        return [
            'total_count'  => $count,                        //总数量
            'current_page' => $page,                         //当前页面
            'limit'        => $limit,                        //每页数量
            'total_page'   => intval(ceil($count / $limit)), //总页码
            'data'         => (object)$data,                         //数据
        ];
    }

    /**
     * [startOperationWhere 启动操作条件]
     *
     * @return object
     */
    public function operationWhere(): object
    {
        $where = (intval($this->is_delete) == 0 && !empty($this->delete_field)) ? [$this->delete_field => 0] : [];
        return $this->where($where);
    }

    private function getFilterRequest($request_data = [])
    {
        $request_data['search'] = trim($request_data['search'] ?? '');
        $primary                = $this->getPrimaryKey();

        !empty($request_data['order']) ? $this->order($primary, $request_data['order']) : $this->order($primary, 'DESC');
        $request_data['order']  = !empty($request_data['order']) ? [$primary => $request_data['order']] : [$primary => 'DESC'];

        $request_data['page']  = intval($request_data['page'] ?? 1);

        $request_data['limit']  = intval($request_data['limit'] ?? 10);
        if ($request_data['limit'] == 0 || !is_numeric($request_data['limit'])) $request_data['limit'] = 10;

        $request_data['where'] = [];
        return $request_data;
    }

    public function setWhereFilter(array $params = [])
    {
        if (isset($params['is_check']) && intval($params['is_check']) != -1) $params['where']['is_check'] = intval($params['is_check']);
        if (isset($params['is_public']) && intval($params['is_public']) != -1) $params['where']['is_public'] = intval($params['is_public']);
        if (isset($params['parent_id']) && intval($params['parent_id']) != -1) $params['where']['parent_id'] = intval($params['parent_id']);
        return $params;
    }

    /**
     * 筛选列表
     *
     * @param $request_data
     * @param $this_model
     *
     * @return mixed
     */
    public function getListFilter($request_data = [])
    {
        $request_data = $this->getFilterRequest($request_data);//对于参数的过滤设置

        //Search搜索
        if (method_exists($this, 'setSearchWhereFilter')) $request_data = $this->setSearchWhereFilter($request_data);

        //是否存在筛选列表
        if (method_exists($this, 'setWhereFilter')) $request_data = $this->setWhereFilter($request_data);

        return $this
            ->where($request_data['where'])
            ->paginate($request_data['limit'], $request_data['page']);
    }

    /**
     * [getDetail 详情]
     *
     * @param integer $id [description]
     *
     * @return [type]      [description]
     */
    public function getDetail($id = 0)
    {
        $detail = $this
            //->with(!empty($this->detailWithModel) ? $this->detailWithModel : $this->withModel)
            ->get($id);
        if (!empty($detail) && method_exists($this, 'set_date_format')) $detail = $this->set_date_format($detail);
        return $detail;
    }

    /**
     * [dataInsert 插入数据]
     *
     * @param array $request_data [description]
     *
     * @return [type]               [description]
     */
    public function dataInsert($request_data = [])
    {
        try {
            if ($model = $this->saveOperation($request_data)) return ['status' => 1, 'msg' => '插入成功！', 'data' => $model->{$this->getPrimaryKey()}];
            else return ['status' => 0, 'msg' => '插入失败！'];
        } catch (\PDOException $e) {
            return ['status' => 0, 'msg' => $e->getMessage()];
        }
    }

    /**
     * [dataUpdate 更新操作]
     *
     * @param array $request_data [description]
     *
     * @return [type]               [description]
     */
    public function dataUpdate($request_data = [])
    {
        try {
            if ($primary = $this->saveOperation($request_data)) return ['status' => 1, 'msg' => '更新成功！', 'data' => $primary];
            else return ['status' => 0, 'msg' => '更新失败！'];
        } catch (\PDOException $e) {
            return ['status' => 0, 'msg' => $e->getMessage()];
        }
    }

    private function saveOperation($request_data)
    {
        // 写库
        $this->connectionName = EasySwooleEvent::setMysqlConnection('write');

        $primary      = $this->getPrimaryKey();
        $request_data = PreProcess::dataFormat($request_data, $this);
        if (!empty($request_data[$primary])) {
            $result = $this->update($request_data, [$primary => $request_data[$primary]]);
        } else {
            $result = $this->data($request_data, true)->save();
        }
        return $result;
    }

    /**
     * 删除操作流程处理
     *
     * @param int $id
     *
     * @return array
     */
    public function dataDelete($id = 0)
    {
        // 写库
        $this->connectionName = EasySwooleEvent::setMysqlConnection('write');

        if (empty($id)) return ['msg' => '主键为必填项！'];
        $primary      = $this->getPrimaryKey();
        $alert_prefix = '{ ' . $primary . ' => ' . $id . ' }';
        if (empty($this_model = $this->get($id))) return ['msg' => $alert_prefix . '不存在！'];

        $operating_state = 0;
        switch (intval($this->is_delete)) {
            case 0:
                $operating_state = $this->where([$primary => $id])->update([$this->delete_field => 1]);
                break;
            case 1:
                $operating_state = $this->destroy($id);
                break;
        }
        if ($operating_state) return ['msg' => $alert_prefix . '删除成功！', 'status' => 1];
        else return $return = ['msg' => $alert_prefix . '删除失败！'];
    }

    /**
     * [changeFiledStatus 指定字段变更]
     *
     * @param array $request_data [description]
     *
     * @return [type]               [description]
     */
    public function changeFiledStatus($request_data = [])
    {
        // 写库
        $this->connectionName = EasySwooleEvent::setMysqlConnection('write');

        $primary = $this->getPrimaryKey();
        if (empty($request_data[$primary])) return ['msg' => '主键为必填项！'];

        $alert_prefix = '{ ' . $primary . ' => ' . $request_data[$primary] . ' }';
        if (empty($this_model = $this->get($request_data[$primary]))) return ['msg' => $alert_prefix . '不存在！'];

        if ($this->where([$primary => $request_data[$primary]])->update([$request_data['change_field'] => $request_data['change_value']]))
            return ['msg' => $alert_prefix . '设置成功！', 'status' => 1];
        else return $return = ['msg' => $alert_prefix . '设置失败！'];
    }

    public function getSelectLists()
    {
        return ['data' => $this->order($this->getPrimaryKey(), 'ASC')->get()];
    }


    public function updateBatch($tableName, $multipleData = [], string $id = 'id')
    {
        // 写库
        $this->connectionName = EasySwooleEvent::setMysqlConnection('write');

        try {
            if (empty($multipleData)) {
                throw new \Exception("数据不能为空");
            }
            $firstRow = current($multipleData);

            $updateColumn = array_keys($firstRow);
            // 默认以id为条件更新，如果没有ID则以第一个字段为条件
            $referenceColumn = isset($firstRow[$id]) ? $id : current($updateColumn);
            unset($updateColumn[0]);
            // 拼接sql语句
            $updateSql = "UPDATE " . $tableName . " SET ";
            $sets      = [];
            $bindings  = [];
            foreach ($updateColumn as $uColumn) {
                $setSql = "`" . $uColumn . "` = CASE ";
                foreach ($multipleData as $data) {
                    $setSql     .= "WHEN `" . $referenceColumn . "` = ? THEN ? ";
                    $bindings[] = $data[$referenceColumn];
                    $bindings[] = $data[$uColumn];
                }
                $setSql .= "ELSE `" . $uColumn . "` END ";
                $sets[] = $setSql;
            }
            $updateSql .= implode(', ', $sets);
            $whereIn   = collect($multipleData)->pluck($referenceColumn)->values()->all();
            $bindings  = array_merge($bindings, $whereIn);
            $whereIn   = rtrim(str_repeat('?,', count($whereIn)), ',');
            $updateSql = rtrim($updateSql, ", ") . " WHERE `" . $referenceColumn . "` IN (" . $whereIn . ")";
            // 传入预处理sql语句和对应绑定数据
            return DB::update($updateSql, $bindings);
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * 获取主键
     *
     * @return string
     * @throws \EasySwoole\ORM\Exception\Exception
     */
    public function getPrimaryKey(): string
    {
        if (isset($this->primaryKey) && !empty($this->primaryKey)) return $this->primaryKey;
        return $this->schemaInfo()->getPkFiledName();
    }
}
